package com.sailing.xjpb.web.base.valid;

import com.google.common.collect.Lists;
import com.sailing.xjpb.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.validation.annotation.Validated;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Set;

/**
 * service层参数标记有@Validated的参数进行拦截并校验合法性，校验不通过抛出参数校验异常
 */
@Slf4j
@Aspect
public class ServiceParameterValidAspect {

    private final Validator validator;

    public ServiceParameterValidAspect(Validator validator) {
        this.validator = validator;
    }


    /**
     * service层方法执行时，进行参数校验
     */
    @Around("execution(public * com.sailing..*(..)) && within(@org.springframework.stereotype.Component * || @org.springframework.stereotype.Service *)")
    public Object doValid(ProceedingJoinPoint pjp) throws Throwable {
        Object target = pjp.getTarget();
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        Method method = methodSignature.getMethod();
        Parameter[] parameters = method.getParameters();
        Object[] args = pjp.getArgs();
        List<String> messages = Lists.newArrayList();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Validated validated = parameter.getAnnotation(Validated.class);
            if (validated == null) {
                continue;
            }
            Set<ConstraintViolation<Object>> validateResults = validator.validate(args[i], validated.value());
            for (ConstraintViolation<Object> constraintViolation : validateResults) {
                String message = constraintViolation.getMessage();
                messages.add(message);
            }
        }
        if (!messages.isEmpty()) {
            String errorMsg = StringUtils.join(messages, "；");
            log.error("参数校验失败：class={}, method={}, errorMsg={}", target.getClass(), method.getName(), errorMsg);
            throw BusinessException.businessError("参数校验失败：" + errorMsg);
        }
        return pjp.proceed();
    }
}